package starter.game.client;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;

import com.bowlong.bio3.B3Helper;
import com.bowlong.bio3.B3InputStream;
import com.bowlong.lang.NumEx;
import com.bowlong.net.TcpChannel;
import com.bowlong.util.NewMap;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class SocketChannel implements TcpChannel {

	final String host;
	final int port;

	boolean isConnection = false;
	Socket socket = null;
	GameCallServiceImp _cgi;

	InputStream in = null;
	OutputStream out = null;

	public SocketChannel(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void setLoop(GameCallServiceImp cgi) {
		this._cgi = cgi;
	}

	public OutputStream getOutput() throws Exception {
		if (socket == null || in == null || out == null || socket.isClosed()
				|| socket.isInputShutdown() || socket.isOutputShutdown()) {

			socket = new Socket(host, port);
			this.in = socket.getInputStream();
			this.out = socket.getOutputStream();

			isConnection = true;

			// startLoop();
		}
		return out;
	}

	public void close() {
		isConnection = false;

		try {
			this.socket.close();
		} catch (Exception e) {
		} finally {
			socket = null;
			in = null;
			out = null;
		}
	}

	// private void startLoop() {
	// ThreadEx.execute(new Runnable() {
	// @Override
	// public void run() {
	// try {
	// while (isConnection || _cgi != null) {
	// // in.read();
	// B2InputStream.readInt(in);
	// NewMap map = B2Helper.toMap(in);
	// System.out.println("CALL = " + map);
	// _cgi.disp(map);
	// }
	// } catch (Exception e) {
	// // System.out.println("RemoteChannel end.");
	// close();
	// }
	// }
	// });
	// }

	@Override
	public int send(Map map) throws Exception {
		try {
			byte[] buff = B3Helper.toBytes(map);
			return send(buff);
		} catch (Exception e) {
			close();
		}
		return 0;
	}

	@Override
	public int send(byte[] buff) throws Exception {
		OutputStream out = getOutput();
		NumEx.writeShort(out, buff.length);
		out.write(buff);
		out.flush();
		return buff.length;
	}

	@Override
	public int readInt() throws Exception {
		return B3InputStream.readInt(in);
	}

	@Override
	public byte[] readBytes(int len) throws Exception {
		return NumEx.readFully(in, len);
	}

	@Override
	public NewMap readMap() throws Exception {
		NumEx.readShort(in);
		Map map = B3InputStream.readMap(in);
		return NewMap.create(map);
	}

}
